// weak_ptr实现
// 解决shared_ptr循环引用问题

#include <iostream>
#include <mutex>

template <typename Type>
class shared_ptr
{
private:
    Type *_pointer;
    int *_count;
    std::mutex *_mutex;

public:
    shared_ptr(Type *pointer) : _pointer(pointer), _count(new int(1)), _mutex(new std::mutex) {}

    shared_ptr(const shared_ptr<Type> &sharedPtr) : _pointer(sharedPtr._pointer), _count(sharedPtr._count), _mutex(sharedPtr._mutex)
    {
        std::cout << "shared_ptr(const shared_ptr<Type> &sharedPtr)" << std::endl;
        addCount();
    }

    shared_ptr<Type> &operator=(shared_ptr<Type> &sharedPtr)
    {
        if (this != &sharedPtr)
        {
            destory();
            _pointer = sharedPtr._pointer;
            _count = sharedPtr._count;
            _mutex = sharedPtr._mutex;
            addCount();
        }
        return *this;
    }

    ~shared_ptr()
    {
        destory();
        std::cout << "~sharedPtr()" << std::endl;
    }
    Type &operator*() { return *_pointer; }
    Type *operator->() { return _pointer; }
    Type *get() const { return _pointer; }
    int use_count() const noexcept { return *_count; }

private:
    void addCount()
    {
        _mutex->lock();
        ++(*_count);
        _mutex->unlock();
    }

    void destory()
    {
        _mutex->lock();
        bool isDestory = false;
        if (--(*_count) == 0 && _pointer != nullptr)
        {
            delete _pointer;
            _pointer = nullptr;
            delete _count;
            _count = nullptr;
            isDestory = true;
        }
        _mutex->unlock();
        if (isDestory)
        {
            delete _mutex;
        }
    }
};

template <typename Type>
class weak_ptr
{
private:
    Type *_pointer;

public:
    weak_ptr() : _pointer(nullptr) {}
    weak_ptr(shared_ptr<Type> &sharedPtr) : _pointer(sharedPtr.get()) { std::cout << "weak_ptr(shared_ptr<Type>& sharedPtr)" << std::endl; }
    Type &operator*() { return *_pointer; }
    Type *operator->() { return _pointer; }
    ~weak_ptr() { std::cout << "~weak_ptr()" << std::endl; }
};

struct Listnode
{
    Listnode() = default;
    weak_ptr<Listnode> _next;
    weak_ptr<Listnode> _prev;
    int data;
    ~Listnode() { std::cout << "~Listnode()" << std::endl; }
};

struct SharedListnode
{
    SharedListnode() : _next(nullptr), _prev(nullptr) {}
    shared_ptr<SharedListnode> _next;
    shared_ptr<SharedListnode> _prev;
    int data;
    ~SharedListnode() { std::cout << "~SharedListnode()" << std::endl; }
};

int main()
{
    shared_ptr<Listnode> l1 = new Listnode;
    shared_ptr<Listnode> l2 = new Listnode;

    //weak_ptr场景 : shared_ptr引用计数不会因为链接而增加,析构shared_ptr时可以直接delelte Listnode
    //场景1
    // l1->_next = l2; // 调用weak_ptr(shared_ptr<Type>& sharedPtr) -> OK

    //场景2
    l1->_next = l2;
    l2->_prev = l1;

    // // 非weak_ptr场景
    // shared_ptr<SharedListnode> ll1 = new SharedListnode;
    // shared_ptr<SharedListnode> ll2 = new SharedListnode;

    // ll1->_next = ll2;
    // ll2->_prev = ll1;

    // std::cout << "ll1 : " << ll1.use_count() << std::endl;
    // std::cout << "ll2 : " << ll2.use_count() << std::endl;

    // ll1->_next -> ll2 | ll2->_prev -> ll1
    // ll1和ll2存储在栈区, 释放后引用计数都为1, 析构shared_ptr时并没有delelte SharedListnode也就导致互相等待对方释放(内存泄漏)

    return 0;
}
